package client

import (
	"context"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"mongoDB"
)

func QueryClientByID(id primitive.ObjectID, ctx context.Context) (*Client, error) {
	queryOne := mongoDB.QueryOne(
		(&Client{}).GetCollection(),
		ctx,
		bson.D{
			{"_id", id},
		},
	)
	oneClient, err := _decodeOneClient(queryOne)
	return oneClient, err
}

func QueryClientByIDNumber(id *string, ctx context.Context) (*Client, error) {
	queryOne := mongoDB.QueryOne(
		(&Client{}).GetCollection(),
		ctx,
		bson.D{
			{"id_number", *id},
		},
	)
	oneClient, err := _decodeOneClient(queryOne)
	return oneClient, err
}

func QueryClientByWXOpenID(openID *string, ctx context.Context) (*Client, error) {
	queryOne := mongoDB.QueryOne(
		(&Client{}).GetCollection(),
		ctx,
		bson.D{
			{"open_id", *openID},
		},
	)
	oneClient, err := _decodeOneClient(queryOne)
	return oneClient, err
}

func QueryClientByPhone(phone *string, ctx context.Context) (*Client, error) {
	queryOne := mongoDB.QueryOne(
		(&Client{}).GetCollection(),
		ctx,
		bson.D{
			{"phone", primitive.Regex{
				Pattern: *phone,
				Options: "i",
			}},
		},
	)
	oneClient, err := _decodeOneClient(queryOne)
	return oneClient, err
}

func _decodeOneClient(sr *mongo.SingleResult) (clientOne *Client, err error) {
	clientOne = new(Client)
	if sr.Err() != nil {
		return clientOne, sr.Err()
	}
	err = sr.Decode(clientOne)
	return
}

func _decodeManyClient(cursor *mongo.Cursor, queryErr error, ctx context.Context) (clientOne *[]Client, err error) {
	if queryErr != nil {
		return nil, queryErr
	}
	result := make([]Client, 0)
	err = cursor.All(ctx, &result)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

func QueryClientByPage(match *bson.D, pageNum int64, pageSize int64, ctx context.Context) (clients *[]Client, total int64, err error) {
	total, cursor, err := mongoDB.FindManyDocumentByPageUseIndex(
		ctx,
		(&Client{}).GetCollection(),
		match,
		nil,
		&pageSize,
		&pageNum,
		nil,
		nil,
	)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return &[]Client{}, 0, nil
		}
		return nil, 0, err
	}
	clients, err = _decodeManyClient(cursor, err, ctx)
	if err != nil {
		return nil, 0, err
	}
	return clients, total, nil
}

/* 简单查找用户,复杂的查询需另写查询语句 */

type FinderClient struct {
	mongoDB.DBFilterBuilder
	model  *Client
	models *[]Client
	Err    error
}

func (f *FinderClient) Result() *Client {
	if f.model != nil {
		return f.model
	}
	return &Client{}
}

func (f *FinderClient) Results() *[]Client {
	if f.model != nil {
		return f.models
	}
	return &[]Client{}
}

func (f *FinderClient) Coach(yes bool) *FinderClient {
	f.AddFilter(&bson.E{Key: "is_coach", Value: yes})
	return f
}

func (f *FinderClient) Error() error {
	return f.Err
}

func (f *FinderClient) Find(ctx context.Context, filter *bson.D, sort *bson.D) error {
	defaultSort := bson.D{{"_id", -1}}
	if sort != nil {
		defaultSort = *sort
	}
	cursor, err := (&Client{}).GetCollection().Find(ctx, *filter, options.Find().SetSort(defaultSort))
	f.models, err = _decodeManyClient(cursor, err, ctx)
	f.Err = err
	return err
}

func (f *FinderClient) First(ctx context.Context, filter *bson.D) (err error) {
	f.model, err = __toolFindOne(ctx, filter, true)
	f.Err = err
	return
}

func (f *FinderClient) Last(ctx context.Context, filter *bson.D) (err error) {
	f.model, err = __toolFindOne(ctx, filter, false)
	f.Err = err
	return
}

func __toolFindOne(ctx context.Context, filter *bson.D, asc bool) (*Client, error) {
	sort := bson.M{"_id": -1}
	if asc {
		sort = bson.M{"_id": 1}
	}
	clientOne, err := _decodeOneClient((&Client{}).GetCollection().FindOne(ctx, *filter, options.FindOne().SetSort(sort)))
	if errors.Is(err, mongo.ErrNoDocuments) {
		err = errors.New("没有找到对应数据")
	}
	return clientOne, err
}
